import { MODEL_META } from '@shared/presenter'
import { IConfigPresenter } from '@shared/presenter'
import { BaseLLMProvider } from '../baseProvider'

interface ModelManagerOptions {
  configPresenter: IConfigPresenter
  getProviderInstance: (providerId: string) => BaseLLMProvider
}

export class ModelManager {
  constructor(private readonly options: ModelManagerOptions) {}

  async getModelList(providerId: string): Promise<MODEL_META[]> {
    console.log(`[ModelManager] getModelList: fetching models for provider "${providerId}"`)
    const provider = this.options.getProviderInstance(providerId)
    let models = await provider.fetchModels()

    console.log(
      `[ModelManager] getModelList: received ${models.length} models from provider "${providerId}"`
    )

    models = models.map((model) => {
      // Validate and fix providerId
      if (model.providerId && model.providerId !== providerId) {
        console.warn(
          `[ModelManager] getModelList: Model ${model.id} has incorrect providerId: expected "${providerId}", got "${model.providerId}". Fixing it.`
        )
        model.providerId = providerId
      } else if (!model.providerId) {
        console.warn(
          `[ModelManager] getModelList: Model ${model.id} missing providerId, setting to "${providerId}"`
        )
        model.providerId = providerId
      }
      const config = this.options.configPresenter.getModelConfig(model.id, providerId)

      model.maxTokens = config.maxTokens
      model.contextLength = config.contextLength

      if (config.isUserDefined) {
        model.vision = config.vision
        model.functionCall = config.functionCall
        model.reasoning = config.reasoning
        model.type = config.type
      } else {
        model.vision = model.vision !== undefined ? model.vision : config.vision
        model.functionCall =
          model.functionCall !== undefined ? model.functionCall : config.functionCall
        model.reasoning = model.reasoning !== undefined ? model.reasoning : config.reasoning
        model.type = model.type || config.type
      }

      return model
    })

    // Final validation
    const incorrectProviderIds = models.filter((m) => m.providerId !== providerId)
    if (incorrectProviderIds.length > 0) {
      console.error(
        `[ModelManager] getModelList: Found ${incorrectProviderIds.length} models with incorrect providerId for provider "${providerId}" after processing`
      )
    } else {
      console.log(
        `[ModelManager] getModelList: returning ${models.length} validated models for provider "${providerId}"`
      )
    }

    return models
  }

  async updateModelStatus(providerId: string, modelId: string, enabled: boolean): Promise<void> {
    this.options.configPresenter.setModelStatus(providerId, modelId, enabled)
  }

  async addCustomModel(
    providerId: string,
    model: Omit<MODEL_META, 'providerId' | 'isCustom' | 'group'>
  ): Promise<MODEL_META> {
    const provider = this.options.getProviderInstance(providerId)
    return provider.addCustomModel(model)
  }

  async removeCustomModel(providerId: string, modelId: string): Promise<boolean> {
    const provider = this.options.getProviderInstance(providerId)
    return provider.removeCustomModel(modelId)
  }

  async updateCustomModel(
    providerId: string,
    modelId: string,
    updates: Partial<MODEL_META>
  ): Promise<boolean> {
    try {
      const provider = this.options.getProviderInstance(providerId)
      const providerResult = await provider.updateCustomModel(modelId, updates)

      // Only update persisted config if provider update was successful
      if (providerResult) {
        await this.options.configPresenter.updateCustomModel(providerId, modelId, updates)
        return true
      } else {
        console.warn(`Provider ${providerId} failed to update model ${modelId}`)
        return false
      }
    } catch (error) {
      console.error(`Failed to update custom model ${modelId} for provider ${providerId}:`, error)
      return false
    }
  }

  async getCustomModels(providerId: string): Promise<MODEL_META[]> {
    try {
      const provider = this.options.getProviderInstance(providerId)
      return provider.getCustomModels()
    } catch (error) {
      console.warn(
        `Failed to get custom models from provider instance ${providerId}, falling back to config:`,
        error
      )
      return this.options.configPresenter.getCustomModels(providerId)
    }
  }
}
